
/**
 *
 * @author Russell
 */
public class RC4 {
    
    private String cipherText;
    private String decryptedText;
    private byte[] plainText;
    private int plainTextLength;
    private byte[] key;
    //private String binaryKey;
    private int keyLength;
    private String keyString;
    private int[] state;
    
    /*
    public void calcBinaryKey() {   // thought I needed this but probably don't...
        for (int i = 0; i < this.keyString.length(); i++) {
            String temp = Integer.toBinaryString(this.keyString.charAt(i));
            int difference = 8 - temp.length();
            for (int j = 0; j < difference; j++) {
                this.binaryKey = this.binaryKey + "0";
            }
            this.binaryKey = this.binaryKey + temp;
        }
    }
     * 
     */
    
    public void keySchedAlg() {
        
        for (int i = 0; i < 256; i++) {
            this.state[i] = i;
        }
        int temp = 0;
        int keyValue = 0;
        int j = 0;
        for (int i = 0; i < 256; i++) {
            /*binValue = this.binaryKey.charAt((i%this.keyLength));
            if(binValue == '1'){
            binValue = 1;
            }
            else{
            binValue = 0;
            }
             * 
             */
            keyValue = this.key[i % this.keyString.length()]; // looks up ascii value from key
            j = (j + this.state[i] + keyValue) % 256;
            temp = this.state[i];   // swap i and j states
            this.state[i] = this.state[j];
            this.state[j] = temp;
        }
    }
    
    public void pRGA() {
        
        int i = 0;
        int j = 0;
        int temp = 0;
        int encryptByte = 0;
        
        for (int k = 0; k < this.plainTextLength; k++) // encrypt plain text bytes
        {
            i = (i + 1) % 256;
            j = (j + this.state[i]) % 256;
            temp = this.state[i];   // swap states
            this.state[i] = this.state[j];
            this.state[j] = temp;
            encryptByte = this.state[(this.state[i] + this.state[j]) % 256];  // this is number to xor stream to encrypt

            int tempCipher = (encryptByte ^ this.plainText[k]);    // this is the xor'd encrypted byte
            String hexString = Integer.toHexString(tempCipher);  
            this.cipherText = this.cipherText + hexString;   // append to string
            
            //decrypt portion
            int tempDecrypted = (encryptByte ^ tempCipher);
            this.decryptedText = this.decryptedText + (char) tempDecrypted;
            
        }
        
    }
    
    public RC4(byte[] plainText) {
        
        this.plainText = new byte[plainText.length];
        this.plainText = plainText;    // plaintext that was input
        this.plainTextLength = this.plainText.length;   // number of bytes to be encrypted
        this.cipherText = "";
        this.decryptedText = "";
        this.keyString = "rc4key";  //40 to 256 bit key, enter whatever or can call from function
        this.key = keyString.getBytes();
        //this.binaryKey = "";
        this.state = new int[256];
        this.keyLength = this.keyString.length() * 8;
        
       // calcBinaryKey();
        keySchedAlg();
        pRGA();
        System.out.println("Using key: " + this.keyString + "\nEncrypted cipher in hex is: " + this.cipherText);
        System.out.println("Decrypted cleartext is: " + this.decryptedText);
    }
}
